home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_500
/
wiconify
/
wiconify-source.lzh
/
Source
/
wGels.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
17KB
|
565 lines
/*
* WICONIFY A utility that allows you to iconify any Intuition window
* on any screen, and to open WB windows on any screen.
*
* wGels.c Handles the Bobs used when icons are dragged.
*
* Copyright 1990 by Davide P. Cervone, all rights reserved.
* You may use this code, provided this copyright notice is kept intact.
*/
#include "wHandler.h"
#include <graphics/gels.h>
static struct Bob *IconBob = NULL; /* List of bobs being dragged */
static WORD LastMouseX,LastMouseY; /* Last place bobs were drawn */
static struct GelsInfo wGelsInfo; /* Blank GelsInfo */
static struct VSprite DummyA,DummyB; /* Dummy sprites for GelsInfo */
#define BOBSHADOW BIT(0) /* Means a shadow was allocated */
#define BOBIMAGE BIT(1) /* Means an Image was allocated */
/*
* Macros for easy memory allocation/deallocation
*/
#define NEWBOB(b) NEWSTRUCT(Bob,b)
#define FREEBOB(b) FREESTRUCT(Bob,b)
#define NEWVSPRITE(s) NEWSTRUCT(VSprite,s)
#define FREEVSPRITE(s) FREESTRUCT(VSprite,s)
#define NEWRASTER(s,i,d) (s = AllocRaster((i)->Width,(i)->Height*d))
#define FREERASTER(s,b,d) FreeRaster(s,SPRITE(b)->VUserExt,SPRITE(b)->Height*d)
#define NEWSHADOW(s,i) NEWRASTER(s,i,1)
#define FREESHADOW(b) FREERASTER((b)->ImageShadow,b,1)
#define NEWSAVE(p,i,s) NEWRASTER(p,i,s->BitMap.Depth)
#define FREESAVE(b,s) FREERASTER((b)->SaveBuffer,b,s->BitMap.Depth)
#define NEWIMAGE(s,i) NEWRASTER(s,i,(i)->Depth)
#define FREEIMAGE(b) FREERASTER(SPRITE(b)->ImageData,b,SPRITE(b)->Depth)
#define SPRITE(b) ((b)->BobVSprite)
/*
* DrawGels()
*
* Get the old screen GelsInfo and replace it by our own
* Sort the Gels for the screen
* Draw the icons on the screen
* Put back the old GelsInfo
*/
static void DrawGels(theScreen)
WSCREEN *theScreen;
{
struct GelsInfo *OldGI;
Forbid();
OldGI = theScreen->Screen->RastPort.GelsInfo;
theScreen->Screen->RastPort.GelsInfo = &wGelsInfo;
SortGList(&(theScreen->Screen->RastPort));
DrawGList(&(theScreen->Screen->RastPort),&(theScreen->Screen->ViewPort));
theScreen->Screen->RastPort.GelsInfo = OldGI;
Permit();
}
/*
* FreeBob()
*
* If we have a bob to work with
* If a shadow was allocated, free it
* If a save buffer was allocated, free it
* If the bob has a sprite
* If the sprite image was allocated, free it
* Free the sprite itself
* Finally, free the bob
*/
static void FreeBob(theBob,theScreen)
struct Bob *theBob;
WSCREEN *theScreen;
{
if (theBob)
{
if (theBob->ImageShadow && (theBob->BUserExt & BOBSHADOW))
FREESHADOW(theBob);
if (theBob->SaveBuffer) FREESAVE(theBob,theScreen->Screen);
if (SPRITE(theBob))
{
if (SPRITE(theBob)->ImageData && (theBob->BUserExt & BOBIMAGE))
FREEIMAGE(theBob);
FREEVSPRITE(SPRITE(theBob));
}
FREEBOB(theBob);
}
}
/*
* DisposeBobs()
*
* While there are more bobs in the list
* Free the bob and go on
* Clear the list pointer
*/
static void DisposeBobs(theScreen)
WSCREEN *theScreen;
{
struct Bob *theBob;
struct Bob *NextBob = IconBob;
while ((theBob = NextBob) != NULL)
{
NextBob = theBob->After;
FreeBob(theBob,theScreen);
}
IconBob = NULL;
}
/*
* MASK calculates the mask for the last word of the sprite data in each row
* sw is the sprite width in words, bw is the width in pixels
*/
#define MASK(bw,sw) ~((1 << (sw * 16 - bw)) - 1)
/*
* MakeMask()
*
* Get the Bob's sprite, and calculate its last image-data word
* Calculate the last-word-of-row mask
* Starting at the end of the sprite data, copy FFFF to each word
* If the mask is not FFFF, go through and trim the final word of each
* row to the correct mask value
*/
static void MakeMask(theBob)
struct Bob *theBob;
{
struct VSprite *theSprite = SPRITE(theBob);
WORD *last = theBob->ImageShadow + theSprite->Width * theSprite->Height - 1;
UWORD theMask = MASK(theSprite->VUserExt,theSprite->Width);
WORD *w;
for (w=last; w >= theBob->ImageShadow; w--) *w = 0xFFFF;
if (theMask != 0xFFFF)
for (w=last; w >= theBob->ImageShadow; w-=theSprite->Width) *w = theMask;
}
/*
* NewBob()
*
* Get the select imagery from the gadget
* If we can allocate a new Bob structure
* An a new VSPRITE structure
* Add the sprite to the bob
* Save the image width (in pixels) in the VUserExt field
* If we can allocate a save buffer of the proper size
* Set the sprite fields appropriately
* Set the sprite's mask (use the Icon's one if it has one,
* otherwise, if this is a default image, use the default mask,
* otherwise try to create a mask for the image, if possible
* otherwise don't use a mask at all
* Mark that everything went OK
* If the Bob was not completely successful, free it and return NULL
*/
static struct Bob *NewBob(theWGadget)
struct wGadget *theWGadget;
{
struct Gadget *theGadget = &(theWGadget->Gadget);
WICONREF *theIcon = (WICONREF *)theGadget->UserData;
struct Bob *theBob;
struct Image *theImage;
struct VSprite *theSprite;
short BobNotOK = TRUE;
if (theGadget->Flags & GADGHIMAGE)
theImage = ((struct Image *)(theGadget->SelectRender));
else
theImage = ((struct Image *)(theGadget->GadgetRender));
if (NEWBOB(theBob))
{
if (NEWVSPRITE(theBob->BobVSprite))
{
theSprite = SPRITE(theBob);
theSprite->VUserExt = theImage->Width;
if (NEWSAVE(theBob->SaveBuffer,theImage,theIcon->Screen->Screen))
{
theSprite->Flags = SAVEBACK | OVERLAY;
theSprite->Height = theImage->Height;
theSprite->Width = (theImage->Width + 15) >> 4;
theSprite->Depth = theImage->Depth;
theSprite->VSBob = theBob;
theSprite->X = theGadget->LeftEdge;
theSprite->Y = theGadget->TopEdge;
if (theIcon->Icon.Mask)
{
theBob->ImageShadow = (WORD *)theIcon->Icon.Mask;
} else if ((theImage == DefaultImage || theImage == DefaultSelect)
&& theImage != NULL && DefaultMask) {
theBob->ImageShadow = DefaultMask->ImageData;
} else if ((theImage == DefaultScreenImage ||
theImage == DefaultScreenSelect)
&& theImage != NULL && DefaultScreenMask) {
theBob->ImageShadow = DefaultScreenMask->ImageData;
} else if (NEWSHADOW(theBob->ImageShadow,theImage)) {
MakeMask(theBob);
theBob->BUserExt |= BOBSHADOW;
} else {
theSprite->Flags &= ~OVERLAY;
}
BobNotOK = FALSE;
}
}
}
if (BobNotOK)
{
FreeBob(theBob,theIcon->Screen);
theBob = NULL;
}
return(theBob);
}
/*
* GetInvertedImage()
*
* Get the Bob's sprite and its select imagery, if any
* Get a pointer to the first gadget on the screen
* Get a pointer to the first Bob in the list
* If the gadget has a select image
* Copy the image information to the sprite
* Otherwise
* Look through the gadget (an bob) list for a gadget with the same image
* If the first one in the list is the gadget we are working on (ie, no
* other gadget has the same image)
* Allocate a raster for the sprite's image, if possible
* Set up dummy BitMaps to point to the sprite data and the image data
* Get the size of the image to be copied, in pixels
* Blit an inverted copy of the image into the sprite's data area
* Mark that the image was allocated
* Otherwise, use the image data area itself (may not be contiguous, tho!)
* Copy the plane pick and on-off (inverted)
* Otherwise (we found a gadget with the same image)
* No need to make another copy, so just duplicate the old values
*/
static void GetInvertedImage(theBob,theGadget,theScreen)
struct Bob *theBob;
struct Gadget *theGadget;
WSCREEN *theScreen;
{
struct VSprite *theSprite = SPRITE(theBob);
struct Image *theImage = (struct Image *)(theGadget->SelectRender);
struct wGadget *CheckGadget = theScreen->Selected;
struct Bob *CheckBob = IconBob;
struct BitMap SrcBitMap, DstBitMap;
long SizeX, SizeY;
char *SrcBytes;
char *DstBytes;
short i;
if (theImage)
{
theSprite->ImageData = theImage->ImageData;
theSprite->PlanePick = theImage->PlanePick;
theSprite->PlaneOnOff = theImage->PlaneOnOff;
} else {
while (CheckGadget->Gadget.GadgetRender != theGadget->GadgetRender)
{
CheckGadget = CheckGadget->NextSelect;
CheckBob = CheckBob->After;
}
if (CheckGadget == (struct wGadget *)theGadget)
{
theImage = (struct Image *)(theGadget->GadgetRender);
if (NEWIMAGE(theSprite->ImageData,theImage))
{
SrcBytes = (char *) theImage->ImageData;
DstBytes = (char *) theSprite->ImageData;
SrcBitMap.BytesPerRow = theSprite->Width * 2;
SrcBitMap.Rows = theSprite->Height;
SrcBitMap.Flags = 0;
SrcBitMap.Depth = theSprite->Depth;
for (i=0; i<SrcBitMap.Depth; i++)
SrcBitMap.Planes[i] = (PLANEPTR) (SrcBytes +
(SrcBitMap.BytesPerRow * SrcBitMap.Rows) * i);
DstBitMap.BytesPerRow = theSprite->Width * 2;
DstBitMap.Rows = theSprite->Height;
DstBitMap.Flags = 0;
DstBitMap.Depth = theSprite->Depth;
for (i=0; i<DstBitMap.Depth; i++)
DstBitMap.Planes[i] = (PLANEPTR) (DstBytes +
(DstBitMap.BytesPerRow * DstBitMap.Rows) * i);
SizeX = SrcBitMap.BytesPerRow * 8;
SizeY = SrcBitMap.Rows;
#define BLT_COPYINVERT 0x30
BltBitMap(&SrcBitMap,0L,0L,&DstBitMap,0L,0L,SizeX,SizeY,
BLT_COPYINVERT,0xFF,NULL);
theBob->BUserExt |= BOBIMAGE;
} else {
theSprite->ImageData = theImage->ImageData;
}
theSprite->PlanePick = theImage->PlanePick;
theSprite->PlaneOnOff = ~(theImage->PlaneOnOff);
} else {
theSprite->ImageData = CheckBob->BobVSprite->ImageData;
theSprite->PlanePick = CheckBob->BobVSprite->PlanePick;
theSprite->PlaneOnOff = CheckBob->BobVSprite->PlaneOnOff;
}
}
}
/*
* CreateBobs()
*
* Get the old GelsInfo from the screen
* Init our GelsInfo and place it in the screen
* While ther are selected gadgets to look at
* If the gadget is allowed tobe moved
* If we can get a new bob for the gadget
* Add the bob to the end of the bob list
* Get its inverted imagery (or select imagery if it has it)
* Add the bob to the screen
* Go on to the next selected gadget
* Put back the old GelsInfo
*/
static void CreateBobs(theScreen)
WSCREEN *theScreen;
{
struct wGadget *theGadget = theScreen->Selected;
struct Bob *theBob;
struct Bob *LastBob = NULL;
struct GelsInfo *OldGI;
Forbid();
OldGI = theScreen->Screen->RastPort.GelsInfo;
InitGels(&DummyA,&DummyB,&wGelsInfo);
theScreen->Screen->RastPort.GelsInfo = &wGelsInfo;
while (theGadget)
{
if ((GADGETICON->Icon.Flags & (WI_NOMOVE| WI_LOCKED)) == FALSE)
{
if (theBob = NewBob(theGadget))
{
if (IconBob == NULL) IconBob = theBob;
if (LastBob) LastBob->After = theBob;
theBob->After = NULL;
theBob->Before = LastBob;
LastBob = theBob;
GetInvertedImage(theBob,theGadget,theScreen);
AddBob(theBob,&(theScreen->Screen->RastPort));
}
}
theGadget = theGadget->NextSelect;
}
theScreen->Screen->RastPort.GelsInfo = OldGI;
Permit();
}
/*
* RemoveBobs()
*
* While there are more bobs in the list
* Request that the bob be removed from the screen
* Draw the gels list (to remove the bobs)
* If the screen's layers were locked, unlock them
* Free the memory used by the bobs
*/
static void RemoveBobs(theScreen)
WSCREEN *theScreen;
{
struct Bob *theBob = IconBob;
while (theBob)
{
RemBob(theBob);
theBob = theBob->After;
}
DrawGels(theScreen);
if (theScreen->Flags & WI_LAYERLOCK)
{
UnlockLayers(&(theScreen->Screen->LayerInfo));
theScreen->Flags &= ~WI_LAYERLOCK;
}
DisposeBobs(theScreen);
}
/*
* SetBobPosition()
*
* While ther are more bobs in the list
* Change the position of the bob and go on to the next one
*/
static void SetBobPosition(dx,dy)
WORD dx,dy;
{
struct Bob *theBob = IconBob;
while (theBob)
{
theBob->BobVSprite->X += dx;
theBob->BobVSprite->Y += dy;
theBob = theBob->After;
}
}
/*
* StartDragging()
*
* Add RMBTRAP to the backdrop window flags (no menus during dragging)
* Add MOUSEMOVEs to the desired Intuition events
* Mark the screen to start dragging on the first mouse move
* Record the mouse position so that move offsets can be calculated
*/
void StartDragging(theIcon,MouseX,MouseY)
WICONREF *theIcon;
WORD MouseX,MouseY;
{
Forbid();
theIcon->Screen->BackDrop->Flags |= RMBTRAP;
ModifyIDCMP(theIcon->Screen->BackDrop,IDCMPFLAGS | MOUSEMOVE);
theIcon->Screen->Flags |= WI_STARTDRAG;
LastMouseX = MouseX;
LastMouseY = MouseY;
Permit();
}
/*
* CancelDragging()
*
* If the screen has icons dragging or is waiting to drag
* If there are bobs, remove them
* Reset the RMPTRAP flag so menus will work again
* Remove the MOUSEMOVE IDCMP flag
* Clear the dragging flags for the screen
*/
void CancelDragging(theScreen)
WSCREEN *theScreen;
{
Forbid();
if (theScreen->Flags & (WI_DRAGGING | WI_STARTDRAG))
{
if (IconBob) RemoveBobs(theScreen);
theScreen->BackDrop->Flags &= ~RMBTRAP;
ModifyIDCMP(theScreen->BackDrop,IDCMPFLAGS);
theScreen->Flags &= ~(WI_DRAGGING | WI_STARTDRAG);
}
Permit();
}
/*
* EndDragging()
*
* If there are bobs and they have been dragged
* Find the layer where the mouse is pointing
* If the layer is the screen's backdrop wIconify window, then
* Move the bobs to their final positions
* Get the change in position of the bobs (from their initial locations)
* Remove the bobs from the screen
* While there are gadgets to be updated
* If the gadget is movable, set its new position
* Go on to the next selected gadget
* Otherwise (icons dropped into some other window)
* Remove the bobs
* Show an error message and "beep" the screen.
* Cancel the dragging
*/
void EndDragging(theScreen,MouseX,MouseY)
WSCREEN *theScreen;
WORD MouseX,MouseY;
{
struct wGadget *theGadget = theScreen->Selected;
struct Layer *theLayer;
WORD dx,dy;
extern struct Layer *WhichLayer();
if (IconBob && (theScreen->Flags & WI_DRAGGING))
{
theLayer = WhichLayer(&(theScreen->Screen->LayerInfo),
MouseX,MouseY + theScreen->BackDrop->TopEdge);
if (theLayer && (struct Window *)theLayer->Window == theScreen->BackDrop)
{
SetBobPosition(MouseX-LastMouseX,MouseY-LastMouseY);
dx = IconBob->BobVSprite->X - theGadget->Gadget.LeftEdge;
dy = IconBob->BobVSprite->Y - theGadget->Gadget.TopEdge;
RemoveBobs(theScreen);
while (theGadget)
{
if ((GADGETICON->Icon.Flags & (WI_NOMOVE| WI_LOCKED)) == FALSE)
MoveGadget(theGadget,dx,dy,theScreen);
theGadget = theGadget->NextSelect;
}
} else {
RemoveBobs(theScreen);
IconError("Icons can't be moved to that window!");
DisplayBeep(theScreen->Screen);
}
}
CancelDragging(theScreen);
}
/*
* MoveGels()
*
* If the bobs have not yet been dragged
* Create the bob list
* If there are bobs to drag
* Lock the screen layers
* Mark the screen as locked and dragging
* Move the bobs to their new position
* Save the current mouse position for later
* Draw the bobs in their new location
*/
void MoveGels(theScreen,MouseX,MouseY)
WSCREEN *theScreen;
WORD MouseX,MouseY;
{
if ((theScreen->Flags & WI_DRAGGING) == FALSE)
{
CreateBobs(theScreen);
if (IconBob)
{
LockLayers(&(theScreen->Screen->LayerInfo));
theScreen->Flags |= WI_DRAGGING | WI_LAYERLOCK;
}
}
SetBobPosition(MouseX-LastMouseX,MouseY-LastMouseY);
LastMouseX = MouseX; LastMouseY = MouseY;
DrawGels(theScreen);
}